/**/

package queue_model;

import java.util.Random;

import javax.swing.JOptionPane;

import simpackNew.Const;
import simpackNew.Sim;
import estatistica.Dispersion;

public class Simulacao {
    public static int simulationNumber = 1;
    
    public static int do_preempt = Const.false_;    // int do_preempt = Const.true_;
    
    // nao considerar mais percentages (nao existe mais porcentagens nas classes A e B, nao existe classes)
    // public static int[] percentages = {10, 20, 25, 30, 40, 50, 60, 70, 75, 80, 90, 100};				// Percentage of ClassA in the system
    // public static int[] percentages = {100};				// Percentage of ClassA in the system     
    // public static int[] contracts = {5, 10, 20, 30, 40, 50}; 			// Variation of contracts in relation to FIFO
    // public static int amountOfSceneries = percentages.length;
    // public static int amountOfSceneries = percentages.length * contracts.length;
    public static int scenery;							// Scenery descriptor
	
    public static double mRt = 0.0;							// Mean residence time (simpack report)
    public static double sum = 0.0;
    public static double average = 0.0;
    public static double additionOfSquares = 0.0;
    public static double contractsDeviation = 0.0;
    
    /* modified by Priscila - inicio */
    // public static int[] n_users = {1, 2, 5, 10, 20};
    // public static double[][] contract = { {0.0}, {0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}};
    // public static double contract[] = {0.0, 0.0, 0.0, 0.0, 0.0};    
    // public static double contractA = 0.0;
    // public static double contractB = 0.0;
        
    // satisfacao
    // public static double[][][] allFulfilledContracts = new double[Const.N_POLITICS][Const.N_USERS][simulationNumber];
    // tempos de resposta que ficaram abaixo do contrato
    // public static double[][][] allLatenciesBelowAverage = new double[Const.N_POLITICS][Const.N_USERS][simulationNumber];
    
    /* modified by Priscila - fim */
    
    // public static double[][][] allFulfilledContractsA = new double[Const.N_POLITICS][amountOfSceneries][simulationNumber * Const.N_USERS_A];
    // public static double[][][] allFulfilledContractsB = new double[Const.N_POLITICS][amountOfSceneries][simulationNumber * Const.N_USERS_B];
       
    // public static double[][][] allLatenciesBelowAverageA = new double[Const.N_POLITICS][amountOfSceneries][simulationNumber * Const.N_USERS_A];
    // public static double[][][] allLatenciesBelowAverageB = new double[Const.N_POLITICS][amountOfSceneries][simulationNumber * Const.N_USERS_B];
    
    public static void simulateCase(QueueModel test, int politicType, int simID, int contracts_deviation, int users_number, double[] contract) {
    // public static void simulateCase(QueueModel test, int politicType, int simID, int perc, int cVar) {
	    // ************** Simulate Politics **************
	    /* modified by Priscila */
    	
        // satisfaction
        double[][][] allFulfilledContracts = new double[Const.N_POLITICS][users_number][simulationNumber];
        // response times below average
        double[][][] allLatenciesBelowAverage = new double[Const.N_POLITICS][users_number][simulationNumber];
        
    	test = new QueueModel(politicType, do_preempt, simID, contracts_deviation, users_number, contract);
	    //test = new QueueModel(politicType, do_preempt, simID, perc, cVar, contractA, contractB);
	    test.simulate();
	    
	    /* Modified by Priscila - start */
	    for (int i = 0; i < users_number; i++) {
	    	System.arraycopy(test.fulfilledContracts, i, allFulfilledContracts[politicType][i], (simID - 1), 1);
	    	System.arraycopy(test.latenciesBelowAverage, i, allLatenciesBelowAverage[politicType][i], (simID - 1), 1);
	    }
	    /* Modified by Priscila - end */
	    
	    // ClassA data update
	    // System.arraycopy(test.fulfilledContracts, 0, allFulfilledContractsA[politicType][scenery], ((simID - 1) * Const.N_USERS_A), Const.N_USERS_A);
	    // System.arraycopy(test.latenciesBelowAverage, 0, allLatenciesBelowAverageA[politicType][scenery], ((simID - 1) * Const.N_USERS_A), Const.N_USERS_A);
	    
	    // ClassB data update	    
	    // System.arraycopy(test.fulfilledContracts, Const.N_USERS_B, allFulfilledContractsB[politicType][scenery], ((simID - 1) * Const.N_USERS_B), Const.N_USERS_B);
	    // System.arraycopy(test.latenciesBelowAverage, Const.N_USERS_B, allLatenciesBelowAverageB[politicType][scenery],((simID - 1) * Const.N_USERS_B), Const.N_USERS_B);
    }
    
    
    public static void main(String[] args) {
    	
    	String n_users = JOptionPane.showInputDialog("Number of Users:");
    	String c_deviation = JOptionPane.showInputDialog("(0) contracts deviation - 0" +
    													"\n\n(1) contracts deviation - 1" +
    													"\n\n(n) contracts deviation - n");
    	
    	int users_number = Integer.parseInt(n_users);
    	int contracts_deviation = Integer.parseInt(c_deviation);
    	
    	System.out.println("users_number: " + users_number + "\tcontracts_deviation: " + contracts_deviation);
    	System.out.println("squares_sum esperado: " + (users_number * (contracts_deviation * contracts_deviation) ) );
    	
    	double [] contract = new double[users_number];
 
    	double squares_bounds;
    	double squares_bounds_aux;
    	double sqrt_squares_bounds;
    	double lower_bound;
    	double upper_bound;
    	
    	double diff, square, squares_sum = 0;
    	double variance;
    	double deviation;
    	
    	// Random rn;
    	
    	/**
    	 * IMPORTANT: the amount of politics to be simulated must be defined by Const.N_POLITICS
    	 * */
		for (int sN = 1; sN <= simulationNumber; sN++) {
		    scenery = 0;
		    // for (int p : percentages) {
			
		    	/* modified by Priscila */
				QueueModel test = new QueueModel(Const.FIFO, do_preempt, sN, contracts_deviation, users_number, contract);
				// QueueModel test = new QueueModel(Const.FIFO, do_preempt, n, p, 0, contractA, contractB);
				mRt = test.simulate();	// Simulate FIFO, just to obtain the mean residence time
				System.out.println("mRt esperado: " + mRt + "\taverage inicial: " + average);
				
				if (contracts_deviation == 0) {
					/* modified by Priscila - inicio */
					for (int u = 0; u < users_number; u++) {
					    // contract[u] = mRt;
					    contract[u] = (int) mRt;
					    sum += contract[u];
						// contract[u] = (mRt - ((0.01 * c) * mRt));
					    // contract[u] = (mRt + ((0.01 * c) * mRt));
					}
					average = sum / users_number;
					/* modified by Priscila - fim */
					// }	
				}
				/* modified by Priscila - start */
				else {					
					squares_bounds = users_number * (contracts_deviation * contracts_deviation);
					// System.out.println("squares_bounds: " + squares_bounds);
					
					squares_bounds_aux = squares_bounds;
					// System.out.println("squares_bounds: " + squares_bounds + "\tsquares_bounds_aux: " + squares_bounds_aux);
					
					sqrt_squares_bounds = Math.sqrt(squares_bounds_aux);
					System.out.println("squares_bounds: " + squares_bounds + "\tsqrt_squares_bounds: " + sqrt_squares_bounds);
					
					while ( (sqrt_squares_bounds % (int) sqrt_squares_bounds ) != 0) {
						squares_bounds_aux -= 1;
						System.out.print("decrementa squares_bounds_aux: " + squares_bounds_aux);
						sqrt_squares_bounds = Math.sqrt(squares_bounds_aux);
						System.out.println("\tsqrt_squares_bounds: " + sqrt_squares_bounds);
					}
					
					lower_bound = (int) mRt - sqrt_squares_bounds;
					upper_bound = (int) mRt + sqrt_squares_bounds;
					System.out.println("lower_bound: " + lower_bound + "\tupper_bound: " + upper_bound);
					// System.out.println("upper_bound: " + upper_bound);
					
					// while ( (squares_sum != squares_bounds) || ( (average < mRt - 0.5) || (average > mRt + 0.5) ) ) {
					while ( (squares_sum != squares_bounds) && (average != mRt) ) {
					// while ( (squares_sum != squares_bounds) && ( (int) average != (int) mRt) ) {
						System.out.println( (mRt + 0.5) + " < " + average + " < " + (mRt - 0.5) + "\n");
						// System.out.println("(int) average: " + (int) average + "(int) mRt: " + (int) mRt);
						squares_sum = 0;
						sum = 0;
						for (int u = 0; u < users_number; u++) {
							    // contract[u] = mRt + (u * contracts_deviation);
							    // contract[u] = mRt + u;
								contract[u] = Sim.random( (int) lower_bound, (int) upper_bound);
								
								System.out.print("\ncontract[" + u + "]: " + contract[u]);
								
								while ( ( (contract[u] - (int) mRt) * (contract[u] - (int) mRt) ) > squares_bounds) {
									contract[u] = Sim.random( (int) lower_bound, (int) upper_bound);
									System.out.print("\n * contract[" + u + ": " + contract[u]);
								}
								
								diff = contract[u] - (int) mRt;
								square = diff * diff;
								squares_sum += square;
								
								sum += contract[u];
								System.out.println("\tdiff: " + diff + "\tsquare: " + square +
													"\tsquares_sum: " + squares_sum + "\tsum: " + sum);
								
								// contract[u] = (mRt - ((0.01 * c) * mRt));
							    // contract[u] = (mRt + ((0.01 * c ) * mRt));
						}					    
						average = sum / users_number;
						
						variance = squares_sum / users_number;
						System.out.println("\nvariance: " + variance);
						
						deviation = Math.sqrt(variance);
						System.out.println("deviation: " + deviation);
						
						System.out.println("mRt: " + mRt);
						
						if (average < mRt) {
							System.out.println("distancia mRt e average: " + (mRt - average) );
						}
						else {
							System.out.println("distancia mRt e average: " + (average - mRt) );							
						}
						
						/* modified by Priscila - end */
				    }
					System.out.println("\naverage final: " + average);
					System.out.println( (mRt - 0.5) + " < " + average + " < " + (mRt + 0.5) + "\n");
				}
				
				for(int u = 0; u < users_number; u++) {
					System.out.println("contract[" + u + "]: " + contract[u]);
				}
				
				
				for (int u = 0; u < users_number; u++) {
					additionOfSquares += ( ( (contract[u] - average) * (contract[u] - average) ) / users_number );
				}					
				contractsDeviation = Math.sqrt(additionOfSquares);
				
				System.out.println("average: " + average + "\tmRt: " + mRt);
				System.out.println("contractsDeviation (with average value): " + contractsDeviation);
				
				additionOfSquares = 0.0;
				
				for (int u = 0; u < users_number; u++) {
					additionOfSquares += ( ( (contract[u] - mRt) * (contract[u] - mRt) ) / users_number );
				}					
				contractsDeviation = Math.sqrt(additionOfSquares);
				
				System.out.println("contractsDeviation (with mRt value): " + contractsDeviation);
			
				
			    //simulateCase(test, Const.FIFO, n, p, c);	// ************** FIFO **************				    				    
			    simulateCase(test, Const.EBS, sN, contracts_deviation, users_number, contract);	// ************** EBS Ultima Abordagem **************
			    // simulateCase(test, Const.EBS, n, p, c);	// ************** EBS Ultima Abordagem **************
			    //simulateCase(test, Const.SJF, n, p, c);	// ************** SJF **************
			    
			    scenery++;
			    
			    if (sN == simulationNumber){
			    	System.out.println("End...");
			    }
		}

		// Calculo Satisfação e Latências abaixo média
		//	scenery = 0;
		//	for (int p : percentages)
		//	    for (int c : contracts) {
		//		// FIFO
		//		Dispersion.calculateDeviation(allFulfilledContractsA[Const.FIFO][scenery], p, c, "A", "FIFO", Const.FULFILMENT_PERCENTAGE);
		//		Dispersion.calculateDeviation(allFulfilledContractsB[Const.FIFO][scenery], p, c, "B", "FIFO", Const.FULFILMENT_PERCENTAGE);
		//
		//		Dispersion.calculateDeviation(allLatenciesBelowAverageA[Const.FIFO][scenery], p, c, "A", "FIFO", Const.LATENCIES_BELOW_AVERAGE);
		//		Dispersion.calculateDeviation(allLatenciesBelowAverageB[Const.FIFO][scenery], p, c, "B", "FIFO", Const.LATENCIES_BELOW_AVERAGE);
		//
		//		
		//		// EBS
		//		Dispersion.calculateDeviation(allFulfilledContractsA[Const.EBS][scenery], p, c, "A", "1Abordagem_EBS", Const.FULFILMENT_PERCENTAGE);
		//		Dispersion.calculateDeviation(allFulfilledContractsB[Const.EBS][scenery], p, c, "B", "1Abordagem_EBS", Const.FULFILMENT_PERCENTAGE);
		//		
		//		Dispersion.calculateDeviation(allLatenciesBelowAverageA[Const.EBS][scenery], p, c, "A", "1Abordagem_EBS", Const.LATENCIES_BELOW_AVERAGE);
		//		Dispersion.calculateDeviation(allLatenciesBelowAverageB[Const.EBS][scenery], p, c, "B", "1Abordagem_EBS", Const.LATENCIES_BELOW_AVERAGE);
		//
		//		
		//		// SJF
		//		Dispersion.calculateDeviation(allFulfilledContractsA[Const.SJF][scenery], p, c, "A", "SJF", Const.FULFILMENT_PERCENTAGE);
		//		Dispersion.calculateDeviation(allFulfilledContractsB[Const.SJF][scenery], p, c, "B", "SJF", Const.FULFILMENT_PERCENTAGE);
		//		
		//		Dispersion.calculateDeviation(allLatenciesBelowAverageA[Const.SJF][scenery], p, c, "A", "SJF", Const.LATENCIES_BELOW_AVERAGE);
		//		Dispersion.calculateDeviation(allLatenciesBelowAverageB[Const.SJF][scenery], p, c, "B", "SJF", Const.LATENCIES_BELOW_AVERAGE);
		//
		//		scenery++;
		//	    }
		//
    }
}